<div class="compose-box-button-sentinel" ref:sentinel></div>
<div class="{computedClass}"
     ref:wrapper >
  <ComposeButton {overLimit} {sticky} on:click="onClickButton()" />
</div>
<style>
  .compose-box-button-wrapper {
    /*
     * We want pointer-events only for the sticky button, so use fit-content so that
     * the element doesn't take up the full width, and then set its left margin to
     * auto so that it sticks to the right. fit-content doesn't work in Edge, but
     * that just means that content that is level with the button is not clickable.
     */
    width: -moz-fit-content;
    width: fit-content;
    margin-left: auto;
    display: flex;
    justify-content: flex-end;
  }

  .compose-box-button-sticky {
    position: -webkit-sticky;
    position: sticky;
  }

  :global(.compose-box-button-sticky, .compose-box-button-fixed) {
    z-index: 5000;
    top: calc(var(--fab-gap-top));
  }
</style>
<script>
  import ComposeButton from './ComposeButton.html'
  import { store } from '../../_store/store.js'
  import { importShowComposeDialog } from '../dialog/asyncDialogs/importShowComposeDialog.js'
  import { observe } from 'svelte-extras'
  import { classname } from '../../_utils/classname.js'

  export default {
    oncreate () {
      this.setupIntersectionObservers()
    },
    ondestroy () {
      this.teardownIntersectionObservers()
    },
    store: () => store,
    data: () => ({
      sticky: false
    }),
    computed: {
      timelineInitialized: ({ $timelineInitialized }) => $timelineInitialized,
      computedClass: ({ showSticky, hideAndFadeIn }) => (classname(
        'compose-box-button-wrapper',
        showSticky && 'compose-box-button-sticky',
        hideAndFadeIn
      ))
    },
    methods: {
      observe,
      onClickButton () {
        const { sticky } = this.get()
        if (sticky) {
          // when the button is sticky, we're scrolled down the home timeline,
          // so we should launch a new compose dialog
          this.showDialog()
        } else {
          // else we're actually posting a new toot, let our parent know
          this.fire('postAction')
        }
      },
      async showDialog () {
        (await importShowComposeDialog())()
      },
      setupIntersectionObservers () {
        const { showSticky } = this.get()
        if (!showSticky) {
          return // no need to set up observers if this button can never be sticky (e.g. dialogs)
        }
        const sentinel = this.refs.sentinel

        this.__stickyObserver = new IntersectionObserver(entries => this.onObserve(entries))
        this.__stickyObserver.observe(sentinel)

        // also create a one-shot observer for the $timelineInitialized event,
        // due to a bug in Firefox where when the scrollTop is set
        // manually, the other observer doesn't necessarily fire
        this.observe('timelineInitialized', timelineInitialized => {
          if (timelineInitialized && !this.__oneShotObserver) {
            this.__oneShotObserver = new IntersectionObserver(entries => {
              this.onObserve(entries)
              this.__oneShotObserver.disconnect()
              this.__oneShotObserver = null
            })
            this.__oneShotObserver.observe(sentinel)
          }
        }, { init: false })
      },
      onObserve (entries) {
        this.set({ sticky: !entries[0].isIntersecting })
      },
      teardownIntersectionObservers () {
        if (this.__stickyObserver) {
          this.__stickyObserver.disconnect()
          this.__stickyObserver = null
        }
        if (this.__oneShotObserver) {
          this.__oneShotObserver.disconnect()
          this.__oneShotObserver = null
        }
      }
    },
    components: {
      ComposeButton
    }
  }
</script>
